/*
 * Copyright (c) 2011 Jean-Marc Perronne
 * Ensisa, 12 rue des Freres Lumieres, F-68093 Mulhouse cedex
 * All rights reserved.
 *
 * The copyright of this software is owned by Werner Randelshofer. 
 * You may not use, copy or modify this software, except in  
 * accordance with the license agreement you entered into with  
 * Jean-Marc Perronne. For details see accompanying license terms. 
 */

package fr.uha.ensisa.jmp.drone.boot;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import fr.uha.ensisa.jmp.drone.app.DroneConstants;
import fr.uha.ensisa.jmp.drone.at_commands.AtCommands;
import fr.uha.ensisa.jmp.drone.handler.DroneHandler;
import fr.uha.ensisa.jmp.drone.navdata.Navdata;


public class BootController
{
	private enum BootState {
		launched, booted, bootStart, bootProcessing, bootNavdata, bootAck
	};

	private DroneHandler atHandler;
	private volatile BootState state;
	private int bootRetry;
	private List<BootAction> bootActions;

	public BootController(DroneHandler handler)
	{
		this.atHandler = handler;
		this.bootRetry = 1;
		this.state = BootState.launched;

		this.bootActions = new ArrayList<BootAction>();
	}

	public synchronized boolean booted()
	{
		return this.state == BootState.booted;
	}

	private void checkBootRetry() throws BootException
	{
		System.out.println("boot try :" + this.bootRetry);
		if (this.bootRetry > DroneConstants.MAX_BOOT_RETRY) throw new BootException("max boot iteration done");
	}

	public void control(Navdata data) throws IOException, BootException
	{

		switch (this.state)
		{
			case launched :
				if (data.isInBootstrapMode()) this.state = BootState.bootStart;
				else this.state = BootState.booted;
				return;

			case booted :
				if (data.isInBootstrapMode()) this.state = BootState.bootStart;
				return;

			case bootStart :
				System.out.println("booting sequence launched");
				this.bootRetry = 1;
				this.atHandler.resetSequenceNumber();
				this.atHandler.sendImmediately(AtCommands.LEAVE_BOOTSTRAP_MODE_CDE);
				this.state = BootState.bootProcessing;
				break;

			case bootProcessing :
				this.checkBootRetry();
				if (data.isCommandProcessing())
				{
					System.out.println("booting, drone leaving boot strap mode, sending navdata demo");
					this.state = BootState.bootNavdata;
				}
				break;

			case bootNavdata :
				this.checkBootRetry();
				System.out.println("sending ACK_CONTROL_MODE_CDE");
				this.atHandler.sendImmediately(AtCommands.ACK_CONTROL_MODE_CDE);
				this.state = BootState.bootAck;
				break;

			case bootAck :
				this.checkBootRetry();
				if (!data.isCommandProcessing())
				{
					System.out.println("drone booted");
					this.state = BootState.booted;
					this.doBootActions();
					return;
				}
				break;
		}

		this.bootRetry++;
		this.sleep(10);

	}

	public void doBootActions() throws BootException
	{
		for (BootAction bo : this.bootActions)
		{
			if (!bo.doBootAction()) throw new BootException("boot action failed");
		}
	}

	public void sleep(long duration)
	{
		try
		{
			Thread.sleep(duration);
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}

	public void addBootAction(BootAction a)
	{
		this.bootActions.add(a);
	}

	public void removeBootAction(BootAction a)
	{
		this.bootActions.remove(a);
	}
}
